/*
 * Copyright (c) 2004 - 2012 Eike Stepper (Berlin, Germany) and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Eike Stepper - initial API and implementation
 *    Stefan Winkler - Bug 289445
 */
package org.eclipse.emf.extensions;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;

/**
 * A useful base class for implementing custom {@link IDBAdapter DB adapters}.
 * 
 * @author Eike Stepper
 */
public abstract class DBAdapter {
    private static final String[] SQL92_RESERVED_WORDS= { "ABSOLUTE", "ACTION", "ADD", "AFTER", "ALL", "ALLOCATE", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
            "ALTER", "AND", "ANY", "ARE", "ARRAY", "AS", "ASC", "ASENSITIVE", "ASSERTION", "ASYMMETRIC", "AT", "ATOMIC", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$ //$NON-NLS-12$
            "AUTHORIZATION", "AVG", "BEFORE", "BEGIN", "BETWEEN", "BIGINT", "BINARY", "BIT", "BIT_LENGTH", "BLOB", "BOOLEAN", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$
            "BOTH", "BREADTH", "BY", "CALL", "CALLED", "CASCADE", "CASCADED", "CASE", "CAST", "CATALOG", "CHAR", "CHARACTER", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$ //$NON-NLS-12$
            "CHARACTER_LENGTH", "CHAR_LENGTH", "CHECK", "CLOB", "CLOSE", "COALESCE", "COLLATE", "COLLATION", "COLUMN", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$
            "COMMIT", "CONDITION", "CONNECT", "CONNECTION", "CONSTRAINT", "CONSTRAINTS", "CONSTRUCTOR", "CONTAINS", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
            "CONTINUE", "CONVERT", "CORRESPONDING", "COUNT", "CREATE", "CROSS", "CUBE", "CURRENT", "CURRENT_DATE", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$
            "CURRENT_DEFAULT_TRANSFORM_GROUP", "CURRENT_PATH", "CURRENT_ROLE", "CURRENT_TIME", "CURRENT_TIMESTAMP", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
            "CURRENT_TRANSFORM_GROUP_FOR_TYPE", "CURRENT_USER", "CURSOR", "CYCLE", "DATA", "DATE", "DAY", "DEALLOCATE", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
            "DEC", "DECIMAL", "DECLARE", "DEFAULT", "DEFERRABLE", "DEFERRED", "DELETE", "DEPTH", "DEREF", "DESC", "DESCRIBE", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$
            "DESCRIPTOR", "DETERMINISTIC", "DIAGNOSTICS", "DISCONNECT", "DISTINCT", "DO", "DOMAIN", "DOUBLE", "DROP", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$
            "DYNAMIC", "EACH", "ELEMENT", "ELSE", "ELSEIF", "END", "EQUALS", "ESCAPE", "EXCEPT", "EXCEPTION", "EXEC", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$
            "EXECUTE", "EXISTS", "EXIT", "EXTERNAL", "EXTRACT", "FALSE", "FETCH", "FILTER", "FIRST", "FLOAT", "FOR", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$
            "FOREIGN", "FOUND", "FREE", "FROM", "FULL", "FUNCTION", "GENERAL", "GET", "GLOBAL", "GO", "GOTO", "GRANT", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$ //$NON-NLS-12$
            "GROUP", "GROUPING", "HANDLER", "HAVING", "HOLD", "HOUR", "IDENTITY", "IF", "IMMEDIATE", "IN", "INDICATOR", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$
            "INITIALLY", "INNER", "INOUT", "INPUT", "INSENSITIVE", "INSERT", "INT", "INTEGER", "INTERSECT", "INTERVAL", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$
            "INTO", "IS", "ISOLATION", "ITERATE", "JOIN", "KEY", "LANGUAGE", "LARGE", "LAST", "LATERAL", "LEADING", "LEAVE", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$ //$NON-NLS-12$
            "LEFT", "LEVEL", "LIKE", "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", "LOCATOR", "LOOP", "LOWER", "MAP", "MATCH", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$
            "MAX", "MEMBER", "MERGE", "METHOD", "MIN", "MINUTE", "MODIFIES", "MODULE", "MONTH", "MULTISET", "NAMES", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$
            "NATIONAL", "NATURAL", "NCHAR", "NCLOB", "NEW", "NEXT", "NO", "NONE", "NOT", "NULL", "NULLIF", "NUMERIC", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$ //$NON-NLS-12$
            "OBJECT", "OCTET_LENGTH", "OF", "OLD", "ON", "ONLY", "OPEN", "OPTION", "OR", "ORDER", "ORDINALITY", "OUT", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$ //$NON-NLS-12$
            "OUTER", "OUTPUT", "OVER", "OVERLAPS", "PAD", "PARAMETER", "PARTIAL", "PARTITION", "PATH", "POSITION", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$
            "PRECISION", "PREPARE", "PRESERVE", "PRIMARY", "PRIOR", "PRIVILEGES", "PROCEDURE", "PUBLIC", "RANGE", "READ", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$
            "READS", "REAL", "RECURSIVE", "REF", "REFERENCES", "REFERENCING", "RELATIVE", "RELEASE", "REPEAT", "RESIGNAL", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$
            "RESTRICT", "RESULT", "RETURN", "RETURNS", "REVOKE", "RIGHT", "ROLE", "ROLLBACK", "ROLLUP", "ROUTINE", "ROW", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$
            "ROWS", "SAVEPOINT", "SCHEMA", "SCOPE", "SCROLL", "SEARCH", "SECOND", "SECTION", "SELECT", "SENSITIVE", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$
            "SESSION", "SESSION_USER", "SET", "SETS", "SIGNAL", "SIMILAR", "SIZE", "SMALLINT", "SOME", "SPACE", "SPECIFIC", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$
            "SPECIFICTYPE", "SQL", "SQLCODE", "SQLERROR", "SQLEXCEPTION", "SQLSTATE", "SQLWARNING", "START", "STATE", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$
            "STATIC", "SUBMULTISET", "SUBSTRING", "SUM", "SYMMETRIC", "SYSTEM", "SYSTEM_USER", "TABLE", "TABLESAMPLE", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$
            "TEMPORARY", "THEN", "TIME", "TIMESTAMP", "TIMEZONE_HOUR", "TIMEZONE_MINUTE", "TO", "TRAILING", "TRANSACTION", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$
            "TRANSLATE", "TRANSLATION", "TREAT", "TRIGGER", "TRIM", "TRUE", "UNDER", "UNDO", "UNION", "UNIQUE", "UNKNOWN", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$
            "UNNEST", "UNTIL", "UPDATE", "UPPER", "USAGE", "USER", "USING", "VALUE", "VALUES", "VARCHAR", "VARYING", "VIEW", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$ //$NON-NLS-12$
            "WHEN", "WHENEVER", "WHERE", "WHILE", "WINDOW", "WITH", "WITHIN", "WITHOUT", "WORK", "WRITE", "YEAR", "ZONE" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$ //$NON-NLS-12$

    private final String name;

    private Set<String> reservedWords;

    private final Connection connection;

    public DBAdapter(String name, Connection connection) {
        this.name=name;
        this.connection=connection;
    }

    public Connection getConnection() {
        return connection;
    }

    public String getName() {
        return name;
    }

    //    public String[] listTables() throws SQLException {
    //        Statement statement=null;
    //        ResultSet rSet=null;
    //        try {
    //            statement=connection.createStatement();
    //            rSet=statement.executeQuery(getListTablesSQL());
    //            List<String> result=Lists.newArrayList();
    //            while (rSet.next()) {
    //                result.add(rSet.getString(1));
    //            }
    //            return result.toArray(new String[result.size()]);
    //        } finally {
    //            if (rSet != null)
    //                rSet.close();
    //            if (statement != null)
    //                statement.close();
    //        }
    //    }

    protected abstract String getListTablesSQL();

    //    @Override
    //    public Set<IDBTable> createTables(Iterable<? extends IDBTable> tables) throws DBException {
    //        Set<IDBTable> createdTables=new HashSet<IDBTable>();
    //        Statement statement=null;
    //
    //        try {
    //            statement=connection.createStatement();
    //            for (IDBTable table : tables) {
    //                if (createTable(table)) {
    //                    createdTables.add(table);
    //                }
    //            }
    //        } catch (SQLException ex) {
    //            throw new DBException(ex);
    //        } finally {
    //            DBUtil.close(statement);
    //        }
    //
    //        return createdTables;
    //    }

    //    public boolean createTable(String tableName) throws SQLException {
    //        boolean created=true;
    //
    //        Statement statement=connection.createStatement();
    //        try {
    //            try {
    //                doCreateTable(tableName, statement);
    //            } catch (SQLException ex) {
    //                created=false;
    //            }
    //
    //            validateTable(tableName, statement);
    //            return created;
    //        } finally {
    //            DBUtil.close(statement);
    //        }
    //    }

    //    public Collection<IDBTable> dropTables(Iterable<? extends IDBTable> tables) throws SQLException {
    //        List<IDBTable> droppedTables=new ArrayList<IDBTable>();
    //
    //        for (IDBTable table : tables) {
    //            if (dropTable(table)) {
    //                droppedTables.add(table);
    //            }
    //        }
    //
    //        return droppedTables;
    //    }
    //
    //    protected String getDropTableSQL(String tableName) {
    //        return "DROP TABLE " + tableName; //$NON-NLS-1$
    //    }

    public int getMaxTableNameLength() {
        // Ansi SQL 92 default value
        return 128;
    }

    public int getMaxFieldNameLength() {
        // Ansi SQL 92 default value
        return 128;
    }

    public boolean isTypeIndexable(DBType type) {
        switch (type) {
            case CLOB:
            case BLOB:
            case LONGVARCHAR:
            case LONGVARBINARY:
            case VARBINARY:
            case BINARY:
                return false;

            default:
                return true;
        }
    }

    @Override
    public String toString() {
        return getName();
    }

    //    /**
    //     * @since 2.0
    //     */
    //    protected void doCreateTable(String tableName, Statement statement) throws SQLException {
    //        StringBuilder builder=new StringBuilder();
    //        builder.append("CREATE TABLE "); //$NON-NLS-1$
    //        builder.append(tableName);
    //        builder.append(" ("); //$NON-NLS-1$
    //        appendFieldDefs(builder, tableName, createFieldDefinitions(tableName));
    //        String constraints=createConstraints(tableName);
    //        if (constraints != null) {
    //            builder.append(", "); //$NON-NLS-1$
    //            builder.append(constraints);
    //        }
    //
    //        builder.append(")"); //$NON-NLS-1$
    //        String sql=builder.toString();
    //
    //        statement.execute(sql);
    //
    //        IDBIndex[] indices=table.getIndices();
    //        for (int i=0; i < indices.length; i++) {
    //            createIndex(indices[i], statement, i);
    //        }
    //    }

    //    /**
    //     * @since 2.0
    //     */
    //    protected void createIndex(IDBIndex index, Statement statement, int num) throws SQLException {
    //        IDBTable table=index.getTable();
    //        StringBuilder builder=new StringBuilder();
    //        builder.append("CREATE "); //$NON-NLS-1$
    //        if (index.getType() == IDBIndex.Type.UNIQUE || index.getType() == IDBIndex.Type.PRIMARY_KEY) {
    //            builder.append("UNIQUE "); //$NON-NLS-1$
    //        }
    //
    //        builder.append("INDEX "); //$NON-NLS-1$
    //        builder.append(table);
    //        builder.append("_idx"); //$NON-NLS-1$
    //        builder.append(num);
    //        builder.append(" ON "); //$NON-NLS-1$
    //        builder.append(table);
    //        builder.append(" ("); //$NON-NLS-1$
    //        IDBField[] fields=index.getFields();
    //        for (int i=0; i < fields.length; i++) {
    //            if (i != 0) {
    //                builder.append(", "); //$NON-NLS-1$
    //            }
    //
    //            addIndexField(builder, fields[i]);
    //        }
    //
    //        builder.append(")"); //$NON-NLS-1$
    //        String sql=builder.toString();
    //
    //        statement.execute(sql);
    //    }

    protected void addIndexField(StringBuilder builder, IDBField field) {
        builder.append(field);
    }

    /**
     * @since 2.0
     */
    protected String createConstraints(IDBTable table) {
        return null;
    }

    //    /**
    //     * @since 2.0
    //     */
    //    protected String createFieldDefinition(IDBField field) {
    //        return getTypeName(field) + (field.isNotNull() ? " NOT NULL" : ""); //$NON-NLS-1$ //$NON-NLS-2$
    //    }

    //    protected String getTypeName(IDBField field) {
    //        DBType type=field.getType();
    //        switch (type) {
    //            case BOOLEAN:
    //            case BIT:
    //            case TINYINT:
    //            case SMALLINT:
    //            case INTEGER:
    //            case BIGINT:
    //            case FLOAT:
    //            case REAL:
    //            case DOUBLE:
    //            case DATE:
    //            case TIME:
    //            case TIMESTAMP:
    //            case LONGVARCHAR:
    //            case LONGVARBINARY:
    //            case BLOB:
    //            case CLOB:
    //                return type.toString();
    //
    //            case CHAR:
    //            case VARCHAR:
    //            case BINARY:
    //            case VARBINARY:
    //                return type.toString() + field.formatPrecision();
    //
    //            case NUMERIC:
    //            case DECIMAL:
    //                return type.toString() + field.formatPrecisionAndScale();
    //        }
    //
    //        throw new IllegalArgumentException("Unknown type: " + type); //$NON-NLS-1$
    //    }

    public String[] getSQL92ReservedWords() {
        return SQL92_RESERVED_WORDS;
    }

    public boolean isReservedWord(String word) {
        if (reservedWords == null) {
            reservedWords=new HashSet<String>();
            for (String reservedWord : getReservedWords()) {
                reservedWords.add(reservedWord.toUpperCase());
            }
        }

        word=word.toUpperCase();
        return reservedWords.contains(word);
    }

    protected abstract String[] getReservedWords();

    //    /**
    //     * @since 2.0
    //     */
    //    protected void validateTable(IDBTable table, Statement statement) throws DBException {
    //        int maxRows=1;
    //
    //        try {
    //            maxRows=statement.getMaxRows();
    //            statement.setMaxRows(1);
    //
    //            String sql=null;
    //
    //            try {
    //                StringBuilder builder=new StringBuilder();
    //                builder.append("SELECT "); //$NON-NLS-1$
    //                appendFieldNames(builder, table);
    //                builder.append(" FROM "); //$NON-NLS-1$
    //                builder.append(table);
    //                sql=builder.toString();
    //
    //                ResultSet resultSet=statement.executeQuery(sql);
    //
    //                try {
    //                    ResultSetMetaData metaData=resultSet.getMetaData();
    //                    int columnCount=metaData.getColumnCount();
    //                    if (columnCount != table.getFieldCount()) {
    //                        throw new DBException("DBTable " + table + " has " + columnCount + " columns instead of " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    //                                + table.getFieldCount());
    //                    }
    //                } finally {
    //                    DBUtil.close(resultSet);
    //                }
    //            } catch (SQLException ex) {
    //                throw new DBException("Problem with table " + table + ':' + sql, ex);
    //            } finally {
    //                if (maxRows != 1) {
    //                    statement.setMaxRows(1);
    //                }
    //            }
    //        } catch (SQLException ex) {
    //            throw new DBException(ex);
    //        }
    //    }

    //    private String[] createFieldDefinitions(IDBTable table) {
    //        IDBField[] fields=table.getFields();
    //        int fieldCount=fields.length;
    //
    //        String[] result=new String[fieldCount];
    //        for (int i=0; i < fieldCount; i++) {
    //            IDBField field=fields[i];
    //            result[i]=createFieldDefinition(field);
    //        }
    //
    //        return result;
    //    }
    //
    //    public void appendFieldNames(Appendable appendable, IDBTable table) {
    //        try {
    //            IDBField[] fields=table.getFields();
    //            for (int i=0; i < fields.length; i++) {
    //                IDBField field=fields[i];
    //                if (i != 0) {
    //                    appendable.append(", "); //$NON-NLS-1$
    //                }
    //
    //                String fieldName=field.getName();
    //                appendable.append(fieldName);
    //            }
    //        } catch (IOException canNotHappen) {
    //        }
    //    }
    //
    //    private void appendFieldDefs(Appendable appendable, IDBTable table, String[] defs) {
    //        try {
    //            IDBField[] fields=table.getFields();
    //            for (int i=0; i < fields.length; i++) {
    //                IDBField field=fields[i];
    //                if (i != 0) {
    //                    appendable.append(", "); //$NON-NLS-1$
    //                }
    //
    //                // String fieldName = mangleFieldName(field.getName(), 0);
    //                String fieldName=field.getName();
    //                appendable.append(fieldName);
    //                appendable.append(" "); //$NON-NLS-1$
    //                appendable.append(defs[i]);
    //            }
    //        } catch (IOException canNotHappen) {
    //        }
    //    }

    public DBType adaptType(DBType type) {
        return type;
    }

    public boolean isValidFirstChar(char ch) {
        return true;
    }

    public boolean isDuplicateKeyException(SQLException ex) {
        /* SQL code for duplicate keys is 23001 */
        return "23001".equals(ex.getSQLState());
    }

    public String getSchemaName() throws SQLException {
        return connection.getCatalog();
    }

    //    public void listColumns(String tableName) {
    //        Statement statement=null;
    //        ResultSet rSet=null;
    //        try {
    //            statement=connection.createStatement();
    //            List<String> result=Lists.newArrayList();
    //            rSet=doListColumns(statement, result, tableName);
    //            if (isMSSQLServer(con)) {
    //                ResultSet resultSet=statement.executeQuery("exec sp_columns " + tableName); //$NON-NLS-1$
    //                while (resultSet.next()) {
    //                    String columnName=resultSet.getString("Field"); //$NON-NLS-1$
    //                    result.add(columnName);
    //                }
    //            } else {
    //                ResultSet resultSet=statement.executeQuery("DESCRIBE " + tableName); //$NON-NLS-1$
    //                while (resultSet.next()) {
    //                    String columnName=resultSet.getString("Field"); //$NON-NLS-1$
    //                    result.add(columnName);
    //                }
    //            }
    //            return result.toArray(new String[result.size()]);
    //        } finally {
    //            DBUtil.close(rSet);
    //            DBUtil.close(statement);
    //        }
    //    }

    //    protected abstract ResultSet doListColumns(Statement statement, List<String> result, String tableName) throws SQLException;
}
